iT邦幫忙

2

一次了解 JS 中的 Event loop、Call Stack 與 Task Queue

  • 分享至 

  • xImage
  •  

這次要了解的是運行 JS 中常見的三個名詞。

先講講呼叫堆疊 Call stack 是什麼?

在了解這三個東西之前,我們要先知道 JavaScript 是單執行緒(也叫單線程) single thread 的程式語言,因此一次只能執行一個任務,而 JS 中等待執行的任務會放入一個堆疊,我們叫它為 Call stack

例如以下幾個函式:

function fun1() {
 return 0;
}

function fun2() {
  fun1();
}

function fun3() {
  fun2();
}

fun3();

2019/11/11 修正 感謝 toy9986619 留言指正
在此段程式中,我們先呼叫了 fun3(),因此 Call stack 如下:
https://ithelp.ithome.com.tw/upload/images/20191111/201168830CwatwLFo2.png

fun3() 呼叫了 fun2()
https://ithelp.ithome.com.tw/upload/images/20191111/20116883hsj5N4X7H4.png

fun2() 呼叫了 fun1()
https://ithelp.ithome.com.tw/upload/images/20191111/20116883ey7yWHa9kb.png

之後執行 fun1(),從 Call stack 移除 fun1(),再執行 fun2(),再從 Call stack 移除 fun2()
最後執行 fun3(),清空 Call stack。

了解非同步事件與任務佇列 Task Queue 的部分

雖然 JS 一次只能執行一個任務,但瀏覽器在執行任務時是多執行緒的,因此可以執行好幾個任務,常見的執行緒包括:

  1. JavaScript引擎執行緒
    就是負責解析與執行 JS
  2. GUI執行緒
    渲染瀏覽器的畫面
  3. 定時觸發器執行緒
    經典代表為 setIntervalsetTimeout
  4. 非同步http請求執行緒
  5. 事件觸發執行緒
    例如滑鼠點擊事件

其中,那些瀏覽器執行緒裡面的事件,像是 setTimeoutXMLHttpRequest,滑鼠點擊事件等就屬於非同步事件。

假如非同步事件會和同步事件都一起放進 Call stack,那麼就會造成阻塞,比如我們發出一個 HTTP 的請求,那麼在完成回傳 response 之前,就會因為 JS 單執行緒的特性,我們在網頁上都無法進行其它動作。

為了避免這種問題,非同步事件裡的回呼函式 callback function, 它們會進入到 Task Queue 裡面,等 Call stack 裡面沒有其它任務才會進入到 Call stack 執行。

最後介紹事件迴圈 Event loop

剛剛提到非同步事件會等 Call stack 裡面沒有其它任務才會進入到 Call stack 執行,就是透過 Event loop 去做判斷的,其監測步驟如下:

  1. 看看 Call stack 裡面有沒有任務,沒有就往第2步驟
  2. 看看 Task Queue 裡面有沒有任務,有的話就把最前面的任務移到 Call stack
  3. 執行完任務,再回到第1步驟

影片推薦

最後,本篇文章是我看了以下的影片和一些參考文章做出的內容整理,只有以文字敘述為主,因此想推薦讀者看看以下的影片,影片講者搭配了 JS 運行的動畫做講解,非常清楚明瞭
/images/emoticon/emoticon07.gif

Yes

如果有寫錯的地方歡迎提出,非常感恩~/images/emoticon/emoticon41.gif


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

3
toy9986619
iT邦新手 5 級 ‧ 2019-11-11 11:24:43

討論一下

Stack 資料結構的特性是先進後出
因此 Call stack 那張圖應該是 fun3 在最底下
先執行 fun3,從 fun3 call fun2,fun2 進入 stack,再從 fun2 call fun1,fun1 進入 stack
return 時會從 fun1 開始結束 pop,因此 fun3 的執行時間會是最長的,也是最晚離開 stack 的

harry xie iT邦研究生 1 級 ‧ 2019-11-11 12:21:43 檢舉

啊啊我注意到了哈哈,非常感謝提醒/images/emoticon/emoticon37.gif

function fun1() {
  console.log('fun1 start');
  fun2();
  console.log('fun1 end);
}

可以利用這種小方式去看執行結果,可能會比較清楚

harry xie iT邦研究生 1 級 ‧ 2019-11-12 13:13:04 檢舉

恩恩不錯的建議

我要留言

立即登入留言